/*
 * Copyright 2024 The CHANGLEI Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import 'package:flatterer/src/indicate_border.dart';
import 'package:flutter/material.dart';

/// Created by changlei on 2023/1/11.
///
/// 追随锚点控件的动态弹窗
class FlattererDecoration extends ShapeDecoration {
  /// Creates a shape decoration.
  ///
  /// * If [color] is null, this decoration does not paint a background color.
  /// * If [gradient] is null, this decoration does not paint gradients.
  /// * If [image] is null, this decoration does not paint a background image.
  /// * If [shadows] is null, this decoration does not paint a shadow.
  ///
  /// The [color] and [gradient] properties are mutually exclusive, one (or
  /// both) of them must be null.
  ///
  /// The [anchor] and [indicateSize] must not be null.
  FlattererDecoration({
    Color? color,
    Gradient? gradient,
    DecorationImage? image,
    List<BoxShadow>? shadows,
    Rect? anchor,
    RSize? indicateSize,
    Axis direction = Axis.vertical,
    BorderRadiusGeometry? borderRadius,
    BorderSide side = BorderSide.none,
  }) : this._(
          color: color,
          gradient: gradient,
          image: image,
          shadows: shadows,
          shape: IndicateBorder(
            anchor: anchor,
            indicateSize: indicateSize,
            direction: direction,
            borderRadius: borderRadius,
            side: side,
          ),
        );

  const FlattererDecoration._({
    Color? color,
    Gradient? gradient,
    DecorationImage? image,
    List<BoxShadow>? shadows,
    required ShapeBorder shape,
  }) : super(
          color: color,
          gradient: gradient,
          image: image,
          shadows: shadows,
          shape: shape,
        );

  ShapeBorder get _clipShape {
    final shape = this.shape;
    if (shape is IndicateBorder) {
      return shape.copyWith(indicateSize: RSize.zero);
    } else {
      return shape;
    }
  }

  @override
  Path getClipPath(Rect rect, TextDirection textDirection) {
    return _clipShape.getOuterPath(rect, textDirection: textDirection);
  }

  @override
  bool hitTest(Size size, Offset position, {TextDirection? textDirection}) {
    return _clipShape.getOuterPath(Offset.zero & size, textDirection: textDirection).contains(position);
  }

  @override
  FlattererDecoration? lerpFrom(Decoration? a, double t) {
    if (a == null || a is FlattererDecoration) {
      return FlattererDecoration.lerp(a as FlattererDecoration?, this, t);
    }
    return super.lerpFrom(a, t) as FlattererDecoration?;
  }

  @override
  FlattererDecoration? lerpTo(Decoration? b, double t) {
    if (b == null || b is FlattererDecoration) {
      return FlattererDecoration.lerp(this, b as FlattererDecoration?, t);
    }
    return super.lerpTo(b, t) as FlattererDecoration?;
  }

  /// Linearly interpolate between two shapes.
  ///
  /// Interpolates each parameter of the decoration separately.
  static FlattererDecoration? lerp(FlattererDecoration? a, FlattererDecoration? b, double t) {
    if (a == null && b == null) {
      return null;
    }
    if (a != null && b != null) {
      if (t == 0.0) {
        return a;
      }
      if (t == 1.0) {
        return b;
      }
    }
    return FlattererDecoration._(
      color: Color.lerp(a?.color, b?.color, t),
      gradient: Gradient.lerp(a?.gradient, b?.gradient, t),
      image: t < 0.5 ? a!.image : b!.image,
      shadows: BoxShadow.lerpList(a?.shadows, b?.shadows, t),
      shape: ShapeBorder.lerp(a?.shape, b?.shape, t)!,
    );
  }
}
